#include "StdAfx.h"
#include "Controller.h"
#include "GarbageCollectorInvoker.h"
#include "shlobj.h"
#include <fstream>

Controller::Controller(void) : m_ObjectTracker(m_TypeTracker), m_FinalizerRunLogger(m_ObjectTracker), m_ForcedGCTimeInterval(INFINITE)

{
	WCHAR buf[512];
	if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, buf)))
		throw std::exception("Cannot find config file");

	std::wstring path = std::wstring(buf);
	path.append(L"\\Undisposed\\config.txt");

	std::wifstream configFile(path.c_str());

	std::wstring str;
	// Ignore executable file path
	std::getline(configFile, str);
	// Ignore command line arguments
	std::getline(configFile, str);

	std::wstring logFilePath;
	std::getline(configFile, logFilePath);

	OutputDebugStr(logFilePath.c_str());

	m_FinalizerRunLogger.Initialize(logFilePath);
	
	configFile >> m_ForcedGCTimeInterval;

	std::vector<std::wstring> typeNames;
	std::wstring line;

	while (!configFile.eof())
	{	
		std::getline(configFile, line);
		typeNames.push_back(line);
	}

	m_ObjectTracker.SetTypeFilter(typeNames);
}

STDMETHODIMP Controller::Initialize(CComPtr<IUnknown> pUnk)
{
	CComPtr<ICorProfilerInfo> pICorProfilerInfo = NULL;	
	HRESULT hr = pUnk->QueryInterface(&pICorProfilerInfo);

	if (FAILED(hr))
		return E_FAIL;

	hr = pICorProfilerInfo->QueryInterface(&m_pCorProfilerInfo);

	if (FAILED(hr))
	{
		return E_FAIL;
	}

	hr = m_pCorProfilerInfo->SetEventMask(COR_PRF_MONITOR_CLASS_LOADS 
		| COR_PRF_MONITOR_OBJECT_ALLOCATED 
		| COR_PRF_MONITOR_GC 
		| COR_PRF_ENABLE_OBJECT_ALLOCATED
		| COR_PRF_ENABLE_STACK_SNAPSHOT
		);

	m_TypeTracker.Initialize(m_pCorProfilerInfo);
	m_ObjectTracker.Initialize(m_pCorProfilerInfo);
	m_GCInvoker.Initialize(m_pCorProfilerInfo);

	m_GCInvoker.DoGCEvery(m_ForcedGCTimeInterval == -1 ? INFINITE : m_ForcedGCTimeInterval);	
	return hr;
}

STDMETHODIMP Controller::ObjectAllocated(ObjectID objectId, ClassID classId)
{
	return m_ObjectTracker.ObjectAllocated(objectId, classId);
}

STDMETHODIMP Controller::FinalizeableObjectQueued(DWORD finalizerFlags, ObjectID objectID)
{
	return m_FinalizerRunLogger.FinalizeableObjectQueued(finalizerFlags, objectID);
}

STDMETHODIMP Controller::ClassLoadFinished(ClassID classId,	HRESULT hrStatus)
{
	return m_TypeTracker.ClassLoadFinished(classId, hrStatus);
}

STDMETHODIMP Controller::Shutdown()
{
	return m_FinalizerRunLogger.Shutdown();
}

STDMETHODIMP Controller::AppDomainShutdownStarted()
{
	return S_OK;
}

STDMETHODIMP Controller::SurvivingReferences(ULONG cSurvivingObjectIDRanges,
		ObjectID objectIDRangeStart[  ],
		ULONG cObjectIDRangeLength[  ])
{
	return m_ObjectTracker.SurvivingReferences(cSurvivingObjectIDRanges,
		objectIDRangeStart,
		cObjectIDRangeLength);
}

STDMETHODIMP Controller::MovedReferences( ULONG cMovedObjectIDRanges,
		ObjectID oldObjectIDRangeStart[  ],
		ObjectID newObjectIDRangeStart[  ],
		ULONG cObjectIDRangeLength[  ])
{
	return m_ObjectTracker.MovedReferences(cMovedObjectIDRanges,
		oldObjectIDRangeStart,
		newObjectIDRangeStart,
		cObjectIDRangeLength);
}


Controller::~Controller(void)
{
}
